/**
 * 
 */
package com.devmindset.legoframework.client.mvc;

import java.util.ArrayList;
import com.allen_sauer.gwt.log.client.Log;
import com.devmindset.legoframework.client.mvc.metadata.EventMonitorStory;
import com.smartgwt.client.util.SC;

/**
 * Governs and manages the {@link EventMonitor} controllers used throughout
 * the application.
 * 
 * After a {@link EventMonitor} has been added to the application, it needs
 * to place itself on the registeredControllers list.
 * 
 * In addition, this class server as a single-point-of-contact for outside
 * components to dispatch events to the registered controllers. This is the only
 * way to ask the {@link EventMonitor}s to handle some event.
 * 
 * @author <a href="mailto:ice.penov@devmindset.com">Ice Penov</a>
 */
public final class EventMonitorManager {

  private static ArrayList<EventMonitor> registeredControllers = new ArrayList<EventMonitor>();

  /**
   * No public instantiation; static usage only.
   */
  private EventMonitorManager() {
    ;
  }

  /**
   * Registers the passed controller to the system.
   * 
   * @param controller the controller to be registered
   */
  public static synchronized void register(EventMonitor controller) {
    if (registeredControllers != null) {
      if (registeredControllers.contains(controller)) {
        Log.warn("Controller [ " + controller.myStory() + "] already registered. Skipping registration.");
      } else {
        registeredControllers.add(controller);
        Log.debug("Controller Registered: [ " + controller.myStory() + " ]");
      }
    } else {
    	String msg = "Passed controller for registration was null.";
      Log.error(msg);
      SC.warn(msg);
    }
  }

  /**
   * Dispatched the given event to any registered controllers that is has
   * declared itself that it can handle it.
   * 
   * @param event the event to be dispatched
   */
  public static void dispathEvent(LegoEvent event) {
    boolean handled = false;
    for (EventMonitor controller : registeredControllers) {
      // can you handle it?
      if (canHandleEvent(controller, event)) {
        handled = true;
        Log.debug("Found the controller [ " + controller.myStory()
            + " ] to handle the event [ " + event.getType() + " ]");
        // ok, handle it.
        controller.handleEvent(event);
        Log.debug("Event dispatched to the designated controller [ "
            + event.getType() + " ]");
      }
    }
    if (!handled) {
      // no one can handle the event.
    	String msg = "No one can't handle the broadcasted event [ " + event.getType()
      + " ]. Missing a controller declaration?";
      Log.error(msg);
      SC.warn(msg);
    }
  }

  /**
   * Determines whether the given controller can handle the the given event.
   * 
   * @param controller the controller to be checked
   * @param event the event
   * 
   * @return true if the controller can handle the event; false otherwise
   */
  private static boolean canHandleEvent(EventMonitor controller, LegoEvent event) {
    boolean result = false;
    EventMonitorStory story = controller.myStory();
    if (story != null && event != null) {
      Enum<?>[] types = story.getCanHandle();
      for (int i = 0; i < types.length; i++) {
        if (event.getType().equals(types[i])) {
          result = true;
          break;
        }
      }
    }
    return result;
  }

}